package com.zhang.network.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhang.network.mapper.FriendMapper;
import com.zhang.network.mapper.NetworkUserMapper;
import com.zhang.network.mapper.UserMapper;
import com.zhang.network.model.Friend;
import com.zhang.network.model.NetworkUser;
import com.zhang.network.model.User;
import com.zhang.network.model.recommend.IntelligentRecommendVO;
import com.zhang.network.service.IntelligentRecommendService;
import com.zhang.util.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class IntelligentRecommendServiceImpl implements IntelligentRecommendService {

    @Resource
    UserMapper userMapper;
    @Resource
    FriendMapper friendMapper;
    @Resource
    NetworkUserMapper networkUserMapper;

    /**
     * 1. 查找所有非好友的用户列表
     * 2. 遍历
     * 2.1 判断是否在相同人脉圈内
     * 2.2 判断是否同省、若同省判断是否同市
     * 2.3 判断职业是否相似
     * 2.4 遍历该好友与自己的共同好友数量
     * 3. 根据不同权重给关联度赋值
     */
    @Override
    public List<IntelligentRecommendVO> intelligentRec(User user) {
        List<User> allFriends = getAllFriends(user);
        List<User> allUserList = userMapper.selectList(new QueryWrapper<User>().notIn("id", user.getId()));
        // remove: allUserList.removeAll(allFriends);
        List<User> recommendList = new ArrayList<>();
        if (StringUtils.isNotBlank(allFriends) && allFriends.size() > 0) {
            recommendList = allUserList.stream().filter(item -> !allFriends.contains(item)).collect(Collectors.toList());
        } else {
            recommendList = allUserList;
        }
        List<IntelligentRecommendVO> results = new ArrayList<>();
        for (User recommend : recommendList) {
            IntelligentRecommendVO result = new IntelligentRecommendVO();
            int degree = 1;
            result.setUser(recommend);
            // 2.1
            if (result.setSameNetwork(whetherInSameNetwork(user, recommend))) {
                degree = degree + 10;
            }
            // 2.2.1
            if (result.setSameProvince(whetherInSameProvince(user, recommend))) {
                degree++;
            }
            // 2.2.2
            if (result.setSameCity(whetherInSameCity(user, recommend))) {
                degree++;
            }
            // 2.3
            if (result.setLikeProfession(whetherHaveSameProfession(user, recommend))) {
                degree = degree + 3;
            }
            // 2.4
            int sameFriendN = countSameFriends(user, recommend);
            result.setSameFriendNum(sameFriendN);
            degree = degree + sameFriendN;
            result.setCorrelationDegree(degree);
            results.add(result);
        }

//        results.removeIf(result -> result.getCorrelationDegree()==0);
        // 按照关联度降序排序
        results.sort(Comparator.comparing(IntelligentRecommendVO::getCorrelationDegree).reversed());
        return results;
    }

    /**
     * 2.1
     *
     * @param user
     * @param recommend
     * @return
     */
    public boolean whetherInSameNetwork(User user, User recommend) {
        List<NetworkUser> networkUserList1 = networkUserMapper.selectList(new QueryWrapper<NetworkUser>().eq("user_id", user.getId()));
        List<NetworkUser> networkUserList2 = networkUserMapper.selectList(new QueryWrapper<NetworkUser>().eq("user_id", recommend.getId()));
        List<Integer> networkList1 = networkUserList1.stream().map(NetworkUser::getNetworkId).collect(Collectors.toList());
        List<Integer> networkList2 = networkUserList2.stream().map(NetworkUser::getNetworkId).collect(Collectors.toList());
        return !Collections.disjoint(networkList1, networkList2);
    }


    /**
     * 2.2.1
     *
     * @param user
     * @param recommend
     * @return
     */
    private boolean whetherInSameProvince(User user, User recommend) {
        return user.getProvince().equals(recommend.getProvince());
    }

    /**
     * 2.2.2
     *
     * @param user
     * @param recommend
     * @return
     */
    public boolean whetherInSameCity(User user, User recommend) {
        if (!whetherInSameProvince(user, recommend)) {
            return false;
        }
        return user.getCity().equals(recommend.getCity());
    }

    /**
     * 2.3
     *
     * @param user
     * @param recommend
     * @return
     */
    public boolean whetherHaveSameProfession(User user, User recommend) {
        return user.getProfession().contains(recommend.getProfession()) || recommend.getProfession().contains(user.getProfession());
    }

    /**
     * 2.4
     *
     * @param user
     * @param recommend
     * @return
     */
    public int countSameFriends(User user, User recommend) {
        return friendMapper.sameFriendNum(user.getId(), recommend.getId());
    }

    public List<User> getAllFriends(User user) {
        QueryWrapper<Friend> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", user.getId());
        List<Friend> allFriends = friendMapper.selectList(wrapper);
        if (allFriends.size() > 0) {
            return userMapper.selectBatchIds(allFriends.stream().map(Friend::getFriendId).collect(Collectors.toList()));
        }
        return null;
    }
}
